home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xpaint-2.1.1 / Paint.c < prev    next >
C/C++ Source or Header  |  1995-05-03  |  41KB  |  1,452 lines

  1. /* +-------------------------------------------------------------------+ */
  2. /* | Copyright 1992, 1993, David Koblas (koblas@netcom.com)            | */
  3. /* |                                                                   | */
  4. /* | Permission to use, copy, modify, and to distribute this software  | */
  5. /* | and its documentation for any purpose is hereby granted without   | */
  6. /* | fee, provided that the above copyright notice appear in all       | */
  7. /* | copies and that both that copyright notice and this permission    | */
  8. /* | notice appear in supporting documentation.  There is no           | */
  9. /* | representations about the suitability of this software for        | */
  10. /* | any purpose.  this software is provided "as is" without express   | */
  11. /* | or implied warranty.                                              | */
  12. /* |                                                                   | */
  13. /* +-------------------------------------------------------------------+ */
  14.  
  15. #include <X11/IntrinsicP.h>
  16. #include <X11/StringDefs.h>
  17. #include <X11/cursorfont.h>
  18. #include <X11/ShellP.h>
  19. #include <X11/Xatom.h>
  20. #include "PaintP.h"
  21. #include "xpaint.h"
  22. #include <stdio.h>
  23.  
  24. /*
  25. **  Value at which zoom starts putting in "white" lines
  26. **    between pixels
  27. */
  28. #define ZOOM_THRESH 5
  29.  
  30. extern XRectangle *RectIntersect(XRectangle *, XRectangle *);
  31.  
  32. typedef    void        (*func_t)(Widget, void *, XEvent *, Boolean);
  33. typedef struct data_s {
  34.     func_t        func;
  35.     void        *data;
  36.     int        mask, flag;
  37.     struct data_s    *next;
  38. } data_t;
  39.  
  40. void PwAddChild(Widget, Widget);
  41.  
  42. static void pwSetPixmap(PaintWidget w, Pixmap pix, int flag);
  43. static void fatCallback(Widget, XtPointer, XtPointer);
  44. static void realExposeProc(PaintWidget, XExposeEvent *, Boolean);
  45. static void drawVisibleGrid(PaintWidget, Widget, Boolean, int, int, int, int, int);
  46.  
  47. static XtResource resources[] = {
  48. #define offset(field) XtOffset(PaintWidget, paint.field)
  49.     /* {name, class, type, size, offset, default_type, default_addr}, */
  50.     { XtNcompress, XtCCompress, XtRBoolean, sizeof(Boolean),
  51.       offset(compress), XtRImmediate, (XtPointer)False },
  52.     { XtNreadOnly, XtCReadOnly, XtRBoolean, sizeof(Boolean),
  53.       offset(compress), XtRImmediate, (XtPointer)False },
  54.     { XtNdrawWidth, XtCDrawWidth, XtRInt, sizeof(int),
  55.       offset(drawWidth), XtRImmediate, (XtPointer)512 },
  56.     { XtNdrawHeight, XtCDrawHeight, XtRInt, sizeof(int),
  57.       offset(drawHeight), XtRImmediate, (XtPointer)512 },
  58.     { XtNlineWidth, XtCLineWidth, XtRInt, sizeof(int),
  59.       offset(lineWidth), XtRImmediate, (XtPointer)0 },
  60.     { XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct*),
  61.       offset(fontInfo), XtRString, XtDefaultFont },
  62.     { XtNpattern, XtCPattern, XtRPixmap, sizeof(Pixmap),
  63.       offset(pattern), XtRPixmap, (XtPointer)None },
  64.     { XtNlinePattern, XtCLinePattern, XtRPixmap, sizeof(Pixmap),
  65.       offset(linePattern), XtRPixmap, (XtPointer)None },
  66.     { XtNpixmap, XtCPixmap, XtRPixmap, sizeof(Pixmap),
  67.       offset(sourcePixmap), XtRPixmap, (XtPointer)NULL },
  68.     { XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
  69.       offset(foreground), XtRString, XtDefaultForeground },
  70.     { XtNlineForeground, XtCLineForeground, XtRPixel, sizeof(Pixel),
  71.       offset(lineForeground), XtRString, XtDefaultForeground },
  72.     { XtNsnap, XtCSnap, XtRInt, sizeof(int),
  73.       offset(snap), XtRImmediate, (XtPointer)10 },
  74.     { XtNregionCallback, XtCRegionCallback, XtRCallback, sizeof(XtPointer),
  75.       offset(regionCalls), XtRCallback, (XtPointer)None },
  76.     { XtNsizeChanged, XtCSizeChanged, XtRCallback, sizeof(XtPointer),
  77.       offset(sizecalls), XtRCallback, (XtPointer)None },
  78.     { XtNfatBack, XtCFatBack, XtRCallback, sizeof(XtPointer),
  79.       offset(fatcalls), XtRCallback, (XtPointer)None },
  80.     { XtNundoSize, XtCUndoSize, XtRInt, sizeof(int),
  81.       offset(undoSize), XtRImmediate, (XtPointer)1 },
  82.     { XtNzoom, XtCZoom, XtRInt, sizeof(int),
  83.       offset(zoom), XtRImmediate, (XtPointer)1 },
  84.     { XtNzoomX, XtCZoomX, XtRInt, sizeof(int),
  85.       offset(zoomX), XtRImmediate, (XtPointer)0 },
  86.     { XtNzoomY, XtCZoomY, XtRInt, sizeof(int),
  87.       offset(zoomY), XtRImmediate, (XtPointer)0 },
  88.     { XtNgrid, XtCGrid, XtRBoolean, sizeof(Boolean),
  89.       offset(grid), XtRImmediate, (XtPointer)False },
  90.     { XtNsnapOn, XtCSnapOn, XtRBoolean, sizeof(Boolean),
  91.       offset(snapOn), XtRImmediate, (XtPointer)False },
  92.     { XtNpaint, XtCPaint, XtRWidget, sizeof(Widget),
  93.       offset(paint), XtRImmediate, (XtPointer)None },
  94.     { XtNdirty, XtCDirty, XtRBoolean, sizeof(Boolean),
  95.       offset(dirty), XtRImmediate, (XtPointer)False },
  96.     { XtNfillRule, XtCFillRule, XtRInt, sizeof(int),
  97.       offset(fillRule), XtRImmediate, (XtPointer)FillSolid },
  98.     { XtNlineFillRule, XtCLineFillRule, XtRInt, sizeof(int),
  99.       offset(lineFillRule), XtRImmediate, (XtPointer)FillSolid },
  100.     { XtNdownX, XtCDownX, XtRPosition, sizeof(Position),
  101.       offset(downX), XtRImmediate, (XtPointer)0 },
  102.     { XtNdownY, XtCDownY, XtRPosition, sizeof(Position),
  103.       offset(downY), XtRImmediate, (XtPointer)0 },
  104.     { XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor),
  105.       offset(cursor), XtRString, (XtPointer)"watch" },
  106. #undef offset
  107. };
  108.  
  109. /*
  110. **  Some forward defines.
  111. */
  112. static void InitializeProc(Widget, Widget);
  113. static void DestroyProc(Widget);
  114. static void ResizeProc(Widget);
  115. static void ExposeProc(Widget, XExposeEvent *);
  116. static void RealizeProc(Widget, Mask *, XSetWindowAttributes *);
  117. static Boolean SetValuesProc(Widget, Widget, Widget);
  118. static void GetValuesHook(Widget, ArgList, Cardinal *);
  119. static int QueryGeometryProc(Widget w, XtWidgetGeometry *proposed,
  120.                 XtWidgetGeometry *reply);
  121.  
  122. static XtGeometryResult GeometryManager(Widget w, XtWidgetGeometry *request, XtWidgetGeometry *reply)
  123. {
  124.     *reply = *request;
  125.  
  126.     if ((request->request_mode & CWX) != 0)
  127.         w->core.x = request->x;
  128.     if ((request->request_mode & CWY) != 0)
  129.         w->core.y = request->y;
  130.     if ((request->request_mode & CWWidth) != 0)
  131.         w->core.width = request->width;
  132.     if ((request->request_mode & CWHeight) != 0)
  133.         w->core.height = request->height;
  134.     if ((request->request_mode & CWBorderWidth) != 0)
  135.         w->core.border_width = request->border_width;
  136.  
  137.     return XtGeometryYes;
  138. }
  139.  
  140.  
  141. PaintClassRec paintClassRec = {
  142.   { /* core fields */
  143.     /* superclass        */    (WidgetClass) &compositeClassRec,
  144.     /* class_name        */    "Paint",
  145.     /* widget_size        */    sizeof(PaintRec),
  146.     /* class_initialize        */    NULL,
  147.     /* class_part_initialize    */    NULL,
  148.     /* class_inited        */    FALSE,
  149.     /* initialize        */    (XtInitProc)InitializeProc,
  150.     /* initialize_hook        */    NULL,
  151.     /* realize            */    RealizeProc,
  152.     /* actions            */    NULL,
  153.     /* num_actions        */    0,
  154.     /* resources        */    resources,
  155.     /* num_resources        */    XtNumber(resources),
  156.     /* xrm_class        */    NULLQUARK,
  157.     /* compress_motion        */    FALSE,
  158.     /* compress_exposure    */    TRUE,
  159.     /* compress_enterleave    */    TRUE,
  160.     /* visible_interest        */    FALSE,
  161.     /* destroy            */    DestroyProc,
  162.     /* resize            */    ResizeProc,
  163.     /* expose            */    (XtExposeProc)ExposeProc,
  164.     /* set_values        */    (XtSetValuesFunc)SetValuesProc,
  165.     /* set_values_hook        */    NULL,
  166.     /* set_values_almost    */    XtInheritSetValuesAlmost,
  167.     /* get_values_hook        */    GetValuesHook,
  168.     /* accept_focus        */    NULL,
  169.     /* version            */    XtVersion,
  170.     /* callback_private        */    NULL,
  171.     /* tm_table            */    NULL,
  172.     /* query_geometry        */    (XtGeometryHandler)QueryGeometryProc,
  173.     /* display_accelerator    */    XtInheritDisplayAccelerator,
  174.     /* extension        */    NULL
  175.   },
  176.   { /* composite fields         */
  177.     /* geometry_manager         */    GeometryManager,
  178.     /* change_managed           */    XtInheritChangeManaged,
  179.     /* insert_child             */    XtInheritInsertChild,
  180.     /* delete_childion          */    XtInheritDeleteChild,
  181.     /* extension                */    NULL,
  182.   },
  183.   { /* paint fields */        
  184.                 0
  185.   }
  186. };
  187.  
  188. WidgetClass paintWidgetClass = (WidgetClass)&paintClassRec;
  189.  
  190. static void undoBuffer(PaintWidget w) 
  191. {
  192.     UndoStack    *new = (UndoStack*)XtMalloc(sizeof(UndoStack));
  193.  
  194.     if (new == NULL)
  195.         return;
  196.  
  197.     new->box.x      = 0;
  198.     new->box.y      = 0;
  199.     new->box.width  = 0;
  200.     new->box.height = 0;
  201.     new->pixmap    = None;
  202.     new->next    = w->paint.head;
  203.     new->prev       = NULL;
  204.     new->valid      = False;
  205.     w->paint.head    = new;
  206.  
  207.     if (w->paint.tail == NULL)
  208.         w->paint.tail = new;
  209.  
  210.     if (new->next != NULL)
  211.         new->next->prev = new;
  212. }
  213.  
  214. static void InitializeProc(Widget w, Widget newArg)
  215. {
  216.     PaintWidget    new = (PaintWidget)newArg;
  217.     int        i;
  218.     int        zoom = new->paint.zoom;
  219.  
  220.     if (zoom == PwZoomParent && new->paint.paint == None)
  221.         zoom = new->paint.zoom = 1;
  222.  
  223.     if (zoom == PwZoomParent)
  224.         zoom = 1;
  225.     else if (zoom <= 0)
  226.         zoom = new->paint.zoom = 1;
  227.  
  228.     if (new->paint.sourcePixmap != None) {
  229.         Window        root;
  230.         int        x, y;
  231.         unsigned int    width, height, bw, depth;
  232.  
  233.         XGetGeometry(XtDisplay(w), new->paint.sourcePixmap,
  234.                 &root, &x, &y, &width, &height, &bw, &depth);
  235.         
  236.         new->paint.drawWidth  = width;
  237.         new->paint.drawHeight = height;
  238.     } else if (new->paint.paint != None) {
  239.         PaintWidget    parent = (PaintWidget)new->paint.paint;
  240.  
  241.         new->paint.drawWidth  = parent->paint.drawWidth;
  242.         new->paint.drawHeight = parent->paint.drawHeight;
  243.     }
  244.  
  245.     if (new->core.width == 0)
  246.         new->core.width = new->paint.drawWidth * zoom;
  247.     if (new->core.height == 0)
  248.         new->core.height = new->paint.drawHeight * zoom;
  249.  
  250.     new->paint.foreground = BlackPixelOfScreen(XtScreen(new));
  251.     new->paint.background = WhitePixelOfScreen(XtScreen(new));
  252.  
  253.     new->paint.gc  = None;
  254.     new->paint.igc = None;
  255.     new->paint.sgc = None;
  256.     new->paint.fgc = None;
  257.     new->paint.mgc = None;
  258.     new->paint.xgc = None;
  259.     new->paint.tgc = None;
  260.  
  261.     /*
  262.     **  Init the undo stuff
  263.     */
  264.     new->paint.tail = NULL;
  265.     new->paint.undo = NULL;
  266.     new->paint.head = NULL;
  267.  
  268.  
  269.     /*
  270.     **  The region information
  271.     */
  272.     new->paint.region.isVisible = False;
  273.     new->paint.region.mask   = None;
  274.     new->paint.region.source = None;
  275.     new->paint.region.notMask= None;
  276.     new->paint.region.inited = False;
  277.     new->paint.region.fg_gc  = None;
  278.     new->paint.region.bg_gc  = None;
  279.     new->paint.region.child  = None;
  280.     new->paint.region.sourceImg = NULL;
  281.     new->paint.region.maskImg   = NULL;
  282.     new->paint.region.notMaskImg= NULL;
  283.     new->paint.region.proc      = NULL;
  284.  
  285.     if (new->paint.paint == None || new->paint.readOnly)
  286.         for (i = 0; i < new->paint.undoSize; i++)
  287.             undoBuffer(new);
  288.  
  289.     for (i = 0; i < XtNumber(new->paint.region.grip); i++)
  290.         new->paint.region.grip[i] = None;
  291.     
  292.     /*
  293.     **  Now the backing store image
  294.     */
  295.     new->paint.image = NULL;
  296.  
  297.     /*
  298.     **
  299.     */
  300.     new->paint.paintGone = False;
  301.     new->paint.paintChildrenSize = 0;
  302.     new->paint.paintChildren = NULL;
  303. }
  304.  
  305. static XRectangle *GetRectangle(PaintWidget w)
  306. {
  307.     static XRectangle    rect;
  308.     XRectangle        *rp = &rect, newRect;
  309.     Widget            cur;
  310.     Widget            prev = (Widget)w;
  311.     int            dx, dy;
  312.  
  313.     rect.x      = dx = 0;
  314.     rect.y      = dy = 0;
  315.     rect.width  = w->core.width  - dx;
  316.     rect.height = w->core.height - dy;
  317.  
  318.     /*
  319.     **  Climb the tree to find the visible area.
  320.     **
  321.     */
  322.     for (cur = XtParent((Widget)w); !XtIsShell(cur); cur = XtParent(cur)) {
  323.         dx += -prev->core.x;
  324.         dy += -prev->core.y;
  325.         newRect.x      = dx;
  326.         newRect.y      = dy;
  327.         newRect.width  = cur->core.width;
  328.         newRect.height = cur->core.height;
  329.  
  330.         rp = RectIntersect(&newRect, rp);
  331.  
  332.         prev = cur;
  333.     }
  334.  
  335.     if (rp != NULL)
  336.         rect = *rp;
  337.     else
  338.         rect.x = rect.y = rect.width = rect.height = 0;
  339.  
  340.     return ▭
  341. }
  342.  
  343. static void RealizeProc(Widget w, Mask *valueMask, 
  344.                 XSetWindowAttributes *attributes)
  345. {
  346.     XWindowAttributes    wattr;
  347.     PaintWidget        pw = (PaintWidget)w;
  348.     PaintWidget        pp = (PaintWidget)pw->paint.paint;
  349.     UndoStack        *cur;
  350.         Window                 root;
  351.         int                     x, y;
  352.         unsigned int           width, height, bw, depth;
  353.     XGCValues        values;
  354.  
  355.     XtCreateWindow(w, InputOutput, CopyFromParent, *valueMask, attributes);
  356.  
  357.         XGetGeometry(XtDisplay(w), XtWindow(w),
  358.                         &root, &x, &y, &width, &height, &bw, &depth);
  359.  
  360.  
  361.     values.foreground = pw->paint.foreground;
  362.     values.background = pw->core.background_pixel;
  363.     pw->paint.gc  = XtGetGC(w, GCForeground|GCBackground, &values);
  364.  
  365.     if (pp == None) {
  366.         /*
  367.         **  Inverse of the base colors.
  368.         */
  369.         values.foreground = pw->core.background_pixel;
  370.         values.background = pw->paint.foreground;
  371.         pw->paint.igc = XCreateGC(XtDisplay(w), XtWindow(w), 
  372.                     GCForeground|GCBackground, &values);
  373.         pw->paint.tgc = XCreateGC(XtDisplay(w), XtWindow(w), 0, 0);
  374.  
  375.         values.function       = GXxor;
  376.         values.foreground     = ~0;
  377.         values.subwindow_mode = IncludeInferiors;
  378.         pw->paint.xgc = XCreateGC(XtDisplay(w), XtWindow(w), 
  379.             GCForeground|GCFunction|GCSubwindowMode, &values);
  380.     } else {
  381.         pw->paint.igc = pp->paint.igc;
  382.         pw->paint.tgc = pp->paint.tgc;
  383.         pw->paint.xgc = pp->paint.xgc;
  384.  
  385.         pw->paint.lineWidth = pp->paint.lineWidth;
  386.     }
  387.  
  388.     /*
  389.     **  Create the filled gc information
  390.     */
  391.     if (pw->paint.paint == None || pw->paint.readOnly) {
  392.         pw->paint.sgc = XCreateGC(XtDisplay(w), XtWindow(w), 0, 0);
  393.         pw->paint.fgc = XCreateGC(XtDisplay(w), XtWindow(w), 0, 0);
  394.         XSetForeground(XtDisplay(w), pw->paint.fgc, pw->paint.foreground);
  395.         XSetForeground(XtDisplay(w), pw->paint.sgc, pw->paint.lineForeground);
  396.  
  397.         /*
  398.         **  First the fill GC
  399.         */
  400.         XSetFillStyle(XtDisplay(w), pw->paint.fgc, pw->paint.fillRule);
  401.         XSetLineAttributes(XtDisplay(w), pw->paint.fgc, 
  402.                 pw->paint.lineWidth, LineSolid, 
  403.                 CapRound, JoinMiter);
  404.         if (pw->paint.pattern != None)
  405.             XSetTile(XtDisplay(w), pw->paint.fgc, pw->paint.pattern);
  406.         if (pw->paint.fontInfo != NULL && pw->paint.fontInfo->fid != None)
  407.             XSetFont(XtDisplay(w), pw->paint.fgc, pw->paint.fontInfo->fid);
  408.  
  409.         /*
  410.         **  Then the line GC
  411.         */
  412.         XSetFillStyle(XtDisplay(w), pw->paint.sgc, pw->paint.lineFillRule);
  413.         XSetLineAttributes(XtDisplay(w), pw->paint.sgc, 
  414.                 pw->paint.lineWidth, LineSolid, 
  415.                 CapRound, JoinMiter);
  416.         if (pw->paint.linePattern != None)
  417.             XSetTile(XtDisplay(w), pw->paint.sgc, pw->paint.linePattern);
  418.     } else if (pw->paint.paint != None) {
  419.         pw->paint.sgc = pp->paint.sgc;
  420.         pw->paint.fgc = pp->paint.fgc;
  421.     }
  422.  
  423.     /*
  424.     **  Parent realized after children, odd..
  425.     */
  426.     if (pp == None && pw->paint.paintChildrenSize != 0) {
  427.         int    i;
  428.         for (i = 0; i < pw->paint.paintChildrenSize; i++) {
  429.             PaintWidget    tp = (PaintWidget)pw->paint.paintChildren[i];
  430.             tp->paint.sgc = pw->paint.sgc;
  431.             tp->paint.fgc = pw->paint.fgc;
  432.             tp->paint.igc = pw->paint.igc;
  433.             tp->paint.xgc = pw->paint.xgc;
  434.             tp->paint.tgc = pw->paint.tgc;
  435.         }
  436.     }
  437.  
  438.     /*
  439.     **  Create the backing undo buffers
  440.     */
  441.     for (cur = pw->paint.tail; cur != NULL; cur = cur->next) {
  442.         cur->pixmap = XCreatePixmap(XtDisplay(w), XtWindow(w), 
  443.                 pw->paint.drawWidth, pw->paint.drawHeight,
  444.                 depth);
  445.         cur->valid = False;
  446.     }
  447.  
  448.     /*
  449.     **  If this paint widgets is the child of another paint
  450.     **   widget then, either creating our own unique information
  451.     **   or just use the information from our parent.
  452.     */
  453.     if (pw->paint.paint == None) {
  454.         pw->paint.base = XCreatePixmap(XtDisplay(w), XtWindow(w), 
  455.                 pw->paint.drawWidth, pw->paint.drawHeight,
  456.                 depth);
  457.         if (pw->paint.sourcePixmap != None)
  458.             pwSetPixmap(pw, pw->paint.sourcePixmap, FALSE);
  459.         else
  460.             XFillRectangle(XtDisplay(w), pw->paint.base, 
  461.                 pw->paint.igc, 0,0, 
  462.                 pw->paint.drawWidth, pw->paint.drawHeight);
  463.     } else {
  464.         PwAddChild(pw->paint.paint, w);
  465.     }
  466.  
  467.     XGetWindowAttributes(XtDisplay(w), XtWindow(w), &wattr);
  468.     pw->paint.visual = wattr.visual;
  469.  
  470.     if (pw->paint.cursor != None)
  471.         XDefineCursor(XtDisplay(pw), XtWindow(pw), pw->paint.cursor);
  472. }
  473.  
  474. static void DestroyProc(Widget w)
  475. {
  476.     PaintWidget    pw = (PaintWidget)w;
  477.     UndoStack    *cur, *nxt;
  478.     int        i;
  479.  
  480.     if (pw->paint.mgc != None)
  481.         XFreeGC(XtDisplay(pw), pw->paint.mgc);
  482.     if (pw->paint.gc != None)
  483.         XtReleaseGC(w, pw->paint.gc);
  484.  
  485.     if (pw->paint.region.source != None)
  486.         XFreePixmap(XtDisplay(pw), pw->paint.region.source);
  487.     if (pw->paint.region.mask != None)
  488.         XFreePixmap(XtDisplay(pw), pw->paint.region.mask);
  489.     if (pw->paint.region.notMask != None)
  490.         XFreePixmap(XtDisplay(pw), pw->paint.region.notMask);
  491.     if (pw->paint.region.sourceImg != NULL)
  492.         XDestroyImage(pw->paint.region.sourceImg);
  493.     if (pw->paint.region.maskImg != NULL)
  494.         XDestroyImage(pw->paint.region.maskImg);
  495.     if (pw->paint.region.notMaskImg != NULL)
  496.         XDestroyImage(pw->paint.region.notMaskImg);
  497.  
  498.     if (pw->paint.paint != None)
  499.         return;
  500.  
  501.     /*  WARNING: the rest of this callback doesn't execute for children */
  502.  
  503.     if (pw->paint.tgc != None)
  504.         XFreeGC(XtDisplay(pw), pw->paint.tgc);
  505.     if (pw->paint.xgc != None)
  506.         XFreeGC(XtDisplay(pw), pw->paint.xgc);
  507.     if (pw->paint.igc != None)
  508.         XFreeGC(XtDisplay(pw), pw->paint.igc);
  509.     if (pw->paint.fgc != None)
  510.         XFreeGC(XtDisplay(pw), pw->paint.fgc);
  511.     if (pw->paint.sgc != None)
  512.         XFreeGC(XtDisplay(pw), pw->paint.sgc);
  513.     
  514.     if (pw->paint.base != None)
  515.         XFreePixmap(XtDisplay(pw), pw->paint.base);
  516.  
  517.     cur = pw->paint.tail;
  518.     while (cur != NULL) {
  519.         nxt = cur->next;
  520.         if (cur->pixmap != None)
  521.             XFreePixmap(XtDisplay(pw), cur->pixmap);
  522.         XtFree((XtPointer)cur);
  523.         cur = nxt;
  524.     }
  525.  
  526.     if (pw->paint.image != NULL) {
  527.         XDestroyRegion(pw->paint.imageRegion);
  528.         XDestroyImage(pw->paint.image);
  529.     }
  530.  
  531.     for (i = 0; i < pw->paint.paintChildrenSize; i++) {
  532.         PaintWidget    tpw = (PaintWidget)pw->paint.paintChildren[i];
  533.  
  534.         tpw->paint.paintGone = True;
  535.     }
  536.  
  537.     if (pw->paint.paintChildren != NULL)
  538.         XtFree((XtPointer)pw->paint.paintChildren);
  539. }
  540.  
  541. static void ResizeProc(Widget w)
  542. {
  543.     /* printf("Resize called, this shouldn't happen!!\n"); */
  544. }
  545.  
  546. #if 0
  547. static XRectangle *overlap(XRectangle *a, XRectangle *b)
  548. {
  549.         static XRectangle       out;
  550.         int                     w, h;
  551.  
  552.         out.x = MAX(a->x, b->x);
  553.         out.y = MAX(a->y, b->y);
  554.         w     = MIN(a->x + a->width,  b->x + b->width)  - out.x;
  555.         h     = MIN(a->y + a->height, b->y + b->height) - out.y;
  556.  
  557.         if (w <= 0 || h <= 0)
  558.                 return NULL;
  559.  
  560.         out.width  = w;
  561.         out.height = h;
  562.  
  563.         return &out;
  564. }
  565. #endif
  566.  
  567. static void drawVisibleGrid(PaintWidget pw, Widget w, Boolean flag, 
  568.         int zoom, int sx, int sy, int ex, int ey)
  569. {
  570.     static     GC    tgc = None;
  571.     GC        gc;
  572.     Display        *dpy = XtDisplay(w);
  573.     Window        win  = XtWindow(w);
  574.     int        i;
  575.  
  576.     if (zoom == 1)
  577.         return;
  578.  
  579.     if (flag) {
  580.         if (tgc == None) {
  581.             XGCValues    values;
  582.             
  583.             values.foreground = BlackPixelOfScreen(XtScreen(w));
  584.             tgc = XtGetGC(w, GCForeground, &values);
  585.         }
  586.         gc = tgc;
  587.     } else {
  588.         /*
  589.         **  Turning off visible grid, and we need to clear
  590.         **    to no space between pixels... 
  591.         */
  592.         if (zoom <= ZOOM_THRESH) {
  593.             XClearArea(dpy, win, sx, sy, ex - sx, ey - sy, True);
  594.             return;
  595.         }
  596.         gc = pw->paint.igc;
  597.     }
  598.  
  599.     for (i = sx; i < ex; i += zoom)
  600.         XDrawLine(dpy, win, gc, i, sy, i, ey);
  601.     for (i = sy; i < ey; i += zoom) 
  602.         XDrawLine(dpy, win, gc, sx, i, ex, i);
  603. }
  604.  
  605. /*
  606. **  Update the zoomed region as specified by rect.
  607. **    rect is in screen coordinates.
  608. **
  609. **  There are two drawers, the first draws using rectangles
  610. **   the second draws using XImages.
  611. **
  612. */
  613.  
  614. static void zoomDrawRects(PaintWidget pw, Widget w, GC gc, XImage *xim, XImage *mask, Boolean isExpose,
  615.             int xstart, int ystart, int zoom, XRectangle *rect)
  616. {
  617.     static Boolean    *flags = NULL;
  618.     static int    flagsSize = 0;
  619.     Display        *dpy   = XtDisplay(w);
  620.     Window        win    = XtWindow(w);
  621.     int        width  = rect->width;
  622.     int        count  = rect->width * rect->height;
  623.     XRectangle    rects[256];
  624.     int        index, i;
  625.  
  626.     if (flagsSize < count) {
  627.         int    allocSize = (count + 4) * sizeof(Boolean);
  628.         if (flags == NULL)
  629.             flags = (Boolean *)XtMalloc(allocSize);
  630.         else
  631.             flags = (Boolean *)XtRealloc((XtPointer)flags, allocSize);
  632.         flagsSize = count;
  633.     }
  634.  
  635.     memset(flags, 0, flagsSize * sizeof(Boolean));
  636.     if (mask != NULL) {
  637.         int    x, y;
  638.  
  639.         i = 0;
  640.         for (y = rect->y; y < rect->height + rect->y; y++) {
  641.             for (x = rect->x; x < rect->width + rect->x; x++, i++) {
  642.                 if (!XGetPixel(mask, x, y))
  643.                     flags[i] = True;
  644.             }
  645.         }
  646.     }
  647.     for (i = 0; i < XtNumber(rects) && i < count; i++)
  648.         if (zoom > ZOOM_THRESH)
  649.             rects[i].width = rects[i].height = zoom - 1;
  650.         else
  651.             rects[i].width = rects[i].height = zoom;
  652.  
  653.     for (index = 0; index != count; index++) {
  654.         if (!flags[index]) {
  655.             int    xindex = index % width + rect->x;
  656.             int    yindex = index / width + rect->y;
  657.             int    xindexEnd = rect->x + rect->width;
  658.             Pixel    p = xxGetPixel(xim, xindex, yindex);
  659.             int    xpos = (index % width + xstart) * zoom;
  660.             int    ypos = (index / width + ystart) * zoom;
  661.             int    pos, flag;
  662.  
  663.             flag = (isExpose && p == w->core.background_pixel);
  664.  
  665.             XSetForeground(dpy, gc, p);
  666.             for (pos = index, i = 0; pos != count; pos++, xindex++, xpos += zoom) {
  667.                 if (xindex == xindexEnd) {
  668.                     xindex = rect->x;
  669.                     xpos   = xstart * zoom;
  670.                     yindex++;
  671.                     ypos  += zoom;
  672.                 }
  673.                 if (flags[pos] || xxGetPixel(xim, xindex, yindex) != p)
  674.                     continue;
  675.                 flags[pos] = True;
  676.  
  677.                 if (flag)
  678.                     continue;
  679.  
  680.                 rects[i].x = xpos;
  681.                 rects[i].y = ypos;
  682.                 i++;
  683.  
  684.                 if (i == XtNumber(rects)) {
  685.                     XFillRectangles(dpy, win, gc, rects, i);
  686.                     i = 0;
  687.                 }
  688.             }
  689.             if (i > 0) 
  690.                 XFillRectangles(dpy, win, gc, rects, i);
  691.         }
  692.     }
  693. }
  694.  
  695. static void zoomDrawImage(PaintWidget pw, Widget w, GC gc, XImage *xim, XImage *mask, Boolean isExpose,
  696.             int xstart, int ystart, int zoom, XRectangle *rect)
  697. {
  698.     Display        *dpy   = XtDisplay(w);
  699.     int        width  = rect->width;
  700.     int        height = rect->height;
  701.     int        size   = width*zoom * height*zoom * sizeof(long);
  702.     XImage        *dst;
  703.     XImage        *dstMsk = NULL;
  704.     int        x, y, x1, y1, dx, dy;
  705.     int        numDraw = zoom - ((zoom > ZOOM_THRESH) ? 1 : 0);
  706.     int        endX = rect->x + rect->width;
  707.     int        endY = rect->y + rect->height;
  708.  
  709.     dst = XCreateImage(dpy, pw->paint.visual, xim->depth, xim->format, 
  710.                     0, NULL, width * zoom, height * zoom, 32, 0);
  711.     dst->data = (char*)XtMalloc(height * zoom * dst->bytes_per_line);
  712.  
  713.     if (mask != NULL) {
  714.         dstMsk = XCreateImage(dpy, pw->paint.visual, 
  715.                     mask->depth, mask->format, 
  716.                     0, NULL, width*zoom, height*zoom, 8, 0);
  717.         dstMsk->data = (char*)XtMalloc(height * zoom * dstMsk->bytes_per_line);
  718.         memset(dstMsk->data, 0, height * zoom * dstMsk->bytes_per_line);
  719.     }
  720.  
  721.     if (mask == NULL) {
  722.         for (dy = 0, y = rect->y; y < endY; y++, dy += zoom) {
  723.             for (dx = 0, x = rect->x; x < endX; x++, dx += zoom) {
  724.                 Pixel    p;
  725.  
  726.                 p = xxGetPixel(xim, x, y);
  727.         
  728.                 for (y1 = 0; y1 < numDraw; y1++) {
  729.                     for (x1 = 0; x1 < numDraw; x1++) {
  730.                         xxPutPixel(dst, dx + x1, dy + y1, p);
  731.                     }
  732.                     if (numDraw != zoom)
  733.                         xxPutPixel(dst, dx + x1, dy + y1, w->core.background_pixel);
  734.                 }
  735.                 if (numDraw != zoom)
  736.                     for (x1 = 0; x1 < zoom; x1++)
  737.                         xxPutPixel(dst, dx + x1, dy + y1, w->core.background_pixel);
  738.             }
  739.         }
  740.     } else {
  741.         for (dy = 0, y = rect->y; y < endY; y++, dy += zoom) {
  742.             for (dx = 0, x = rect->x; x < endX; x++, dx += zoom) {
  743.                 Pixel    p;
  744.  
  745.                 if (!xxGetPixel(mask, x, y))
  746.                     continue;
  747.  
  748.                 p = xxGetPixel(xim, x, y);
  749.  
  750.                 for (y1 = 0; y1 < numDraw; y1++) {
  751.                     for (x1 = 0; x1 < numDraw; x1++) {
  752.                         xxPutPixel(dst, dx + x1, dy + y1, p);
  753.                         xxPutPixel(dstMsk, dx + x1, dy + y1, True); 
  754.                     }
  755.                 }
  756.             }
  757.         }
  758.     }
  759.  
  760.     if (mask != NULL) {
  761.         Pixmap    pix = XCreatePixmap(XtDisplay(w), XtWindow(w), width * zoom, height * zoom, 1);
  762.  
  763.         XPutImage(XtDisplay(w), pix, pw->paint.mgc, dstMsk, 
  764.                 0, 0, 0, 0, width * zoom, height * zoom);
  765.             
  766.         XSetClipMask(XtDisplay(w), gc, pix);
  767.         XSetClipOrigin(XtDisplay(w), gc, xstart * zoom, ystart * zoom);
  768.         XPutImage(XtDisplay(w), XtWindow(w), gc, dst, 0, 0, 
  769.                 xstart * zoom, ystart * zoom, 
  770.                 width * zoom, height * zoom);
  771.         XSetClipMask(XtDisplay(w), gc, None);
  772.  
  773.         XFreePixmap(XtDisplay(w), pix);
  774.     } else {
  775.         XPutImage(XtDisplay(w), XtWindow(w), gc, dst, 0, 0, 
  776.                 xstart * zoom, ystart * zoom, 
  777.                 width * zoom, height * zoom);
  778.     }
  779.  
  780.     XDestroyImage(dst);
  781.     if (dstMsk != NULL)
  782.         XDestroyImage(dstMsk);
  783. }
  784.  
  785. static void zoomUpdate(PaintWidget pw, Boolean isExpose, XRectangle *rect)
  786. {
  787.     int        zoom = GET_ZOOM(pw);
  788.     int        sx, sy, w, h, zsx, zsy;
  789.     XImage        *xim;
  790.     XRectangle    *isec, *tmp;
  791.     XRectangle    real, grab;
  792.  
  793.     if ((isec = RectIntersect(rect, GetRectangle(pw))) == NULL)
  794.         return;
  795.  
  796.     zsx = sx = isec->x / zoom;
  797.     zsy = sy = isec->y / zoom;
  798.     w  = (isec->width  + (isec->x % zoom) + zoom - 1) / zoom;
  799.     h  = (isec->height + (isec->y % zoom) + zoom - 1) / zoom;
  800.  
  801.     grab.x      = sx + pw->paint.zoomX;
  802.     grab.y      = sy + pw->paint.zoomY;
  803.     grab.width  = w;
  804.     grab.height = h;
  805.     real.x      = 0;
  806.     real.y      = 0;
  807.     real.width  = pw->paint.drawWidth;
  808.     real.height = pw->paint.drawHeight;
  809.  
  810.     if ((tmp = RectIntersect(&grab, &real)) == NULL)
  811.         return;
  812.  
  813.     xim = PwGetImage((Widget)pw, tmp);
  814.  
  815.     real.x      = tmp->x;
  816.     real.y      = tmp->y;
  817.     real.width  = tmp->width;
  818.     real.height = tmp->height;
  819.  
  820.     _PwZoomDraw(pw, (Widget)pw, pw->paint.tgc, xim, NULL, isExpose, sx, sy, zoom, &real);
  821. }
  822. /*
  823. **  pw  = parent paint widget
  824. **  w   = widget who's window will be updated
  825. **  gc  = gc to use (read/written)
  826. **  src = source XImage to use
  827. **  mask = mask XImage to use
  828. **  flag = is this an expose event, so we don't have to update pixels == window background
  829. **  sx,sy = start x, y for window drawing (non-zoomed)
  830. **  zoom = zoom value to apply
  831. **  rect = region of the input ximages to use to draw a start x,y with the specified width,height
  832. */
  833. void _PwZoomDraw(PaintWidget pw, Widget w, GC gc, XImage *src, XImage *mask, Boolean flag,
  834.             int sx, int sy, int zoom, XRectangle *rect)
  835. {
  836.     if (rect->width * rect->height < 1024 + 256)
  837.         zoomDrawRects(pw, w, gc, src, mask, flag, sx, sy, zoom, rect);
  838.     else
  839.         zoomDrawImage(pw, w, gc, src, mask, flag, sx, sy, zoom, rect);
  840.  
  841.     if (pw->paint.grid) {
  842.         int        xstart, xend, ystart, yend;
  843.  
  844.         xstart = sx * zoom - 1;
  845.         ystart = sy * zoom - 1;
  846.         xend   = xstart + rect->width * zoom + zoom - 1;
  847.         yend   = ystart + rect->height * zoom + zoom - 1;
  848.  
  849.         drawVisibleGrid(pw, w, True, zoom, xstart, ystart, xend, yend);
  850.     }
  851. }
  852.  
  853.  
  854. void PwUpdateDrawable(Widget w, Drawable draw, XRectangle *rect)
  855. {
  856.     PaintWidget    pw = (PaintWidget)w;
  857.     XRectangle    all;
  858.     Pixmap        pix = GET_PIXMAP(pw);
  859.  
  860.     if (rect == NULL || rect->width == 0 || rect->height == 0) {
  861.         rect = &all;
  862.         all.x = all.y = 0;
  863.         all.width  = pw->core.width;
  864.         all.height = pw->core.height;
  865.     }
  866.     XCopyArea(XtDisplay(w), pix, draw, pw->paint.gc,
  867.             rect->x + pw->paint.zoomX, 
  868.             rect->y + pw->paint.zoomY,
  869.             rect->width, rect->height,
  870.             rect->x, rect->y);
  871. }
  872.  
  873. static void realExposeProc(PaintWidget pw, XExposeEvent *event, Boolean flag)
  874. {
  875.     int        x, y, width, height;
  876.     XRectangle    rect;
  877.  
  878.     if (!XtIsRealized(((Widget)pw)))
  879.         return;
  880.  
  881.     /*
  882.     **  Clean up the event, since I do simulate them
  883.     */
  884.     x      = event->x;
  885.     y      = event->y;
  886.     width  = event->width;
  887.     height = event->height;
  888.  
  889.     if (x < 0) {
  890.         width += x;
  891.         x = 0;
  892.     }
  893.     if (y < 0) {
  894.         height += y;
  895.         y = 0;
  896.     }
  897.     if (width < 0 || height < 0)
  898.         return;
  899.     if (x > pw->core.width || y > pw->core.height)
  900.         return;
  901.     if (x + width > pw->core.width)
  902.         width = pw->core.width - x;
  903.     if (y + height > pw->core.height)
  904.         height = pw->core.height - y;
  905.  
  906.     rect.x      = x;
  907.     rect.y      = y;
  908.     rect.width  = width;
  909.     rect.height = height;
  910.  
  911.     if (GET_ZOOM(pw) <= 1)
  912.         PwUpdateDrawable((Widget)pw, XtWindow((Widget)pw), &rect);
  913.     else
  914.         zoomUpdate(pw, flag, &rect);
  915. }
  916.  
  917. static void ExposeProc(Widget w, XExposeEvent *event)
  918. {
  919.     realExposeProc((PaintWidget)w, event, True);
  920. }
  921.  
  922. static void resizePixmap(PaintWidget w, Pixmap *pixmap)
  923. {
  924.     Pixmap    n;
  925.  
  926.     if (pixmap == NULL || *pixmap == None)
  927.         return;
  928.  
  929.     n = XCreatePixmap(XtDisplay(w), XtWindow(w), 
  930.                 w->paint.drawWidth, w->paint.drawHeight,
  931.                 w->core.depth);
  932.     XFillRectangle(XtDisplay(w), n, 
  933.                 w->paint.igc, 0,0, 
  934.                 w->paint.drawWidth, w->paint.drawHeight);
  935.     XCopyArea(XtDisplay(w), *pixmap, n,
  936.                 w->paint.gc, 0, 0, 
  937.                 w->paint.drawWidth, w->paint.drawHeight, 0, 0);
  938.     XFreePixmap(XtDisplay(w), *pixmap);
  939.     *pixmap = n;
  940. }
  941.  
  942. static Boolean SetValuesProc(Widget curArg, Widget request, 
  943.                 Widget newArg)
  944. {
  945.     PaintWidget    cur = (PaintWidget)curArg;
  946.     PaintWidget    new = (PaintWidget)newArg;
  947.     int        ret = False;
  948.     int        sizeChanged = False;
  949.     int        i;
  950.  
  951.     if (cur->paint.sourcePixmap != new->paint.sourcePixmap) 
  952.         pwSetPixmap(new, new->paint.sourcePixmap, True);
  953.  
  954.     if (cur->paint.compress != new->paint.compress) 
  955.         new->core.widget_class->core_class.compress_motion = new->paint.compress;
  956.  
  957.     if (!XtIsRealized((Widget)new))
  958.         return ret;
  959.  
  960.     if (cur->paint.fillRule != new->paint.fillRule) 
  961.         XSetFillStyle(XtDisplay(new), new->paint.fgc, new->paint.fillRule);
  962.     if (cur->paint.foreground != new->paint.foreground) 
  963.         XSetForeground(XtDisplay(new), new->paint.fgc, new->paint.foreground);
  964.     if (cur->paint.pattern != new->paint.pattern) 
  965.         XSetTile(XtDisplay(new), new->paint.fgc, new->paint.pattern);
  966.  
  967.     if (cur->paint.lineFillRule != new->paint.lineFillRule) 
  968.         XSetFillStyle(XtDisplay(new), new->paint.sgc, new->paint.lineFillRule);
  969.     if (cur->paint.lineForeground != new->paint.lineForeground) 
  970.         XSetForeground(XtDisplay(new), new->paint.sgc, new->paint.lineForeground);
  971.     if (cur->paint.linePattern != new->paint.linePattern) 
  972.         XSetTile(XtDisplay(new), new->paint.sgc, new->paint.linePattern);
  973.  
  974.     if (cur->paint.lineWidth != new->paint.lineWidth) {
  975.         XSetLineAttributes(XtDisplay(new), new->paint.fgc, 
  976.                 new->paint.lineWidth, LineSolid, 
  977.                 CapRound, JoinMiter);
  978.         XSetLineAttributes(XtDisplay(new), new->paint.sgc, 
  979.                 new->paint.lineWidth, LineSolid, 
  980.                 CapRound, JoinMiter);
  981.     }
  982.     if (cur->paint.fontInfo->fid != new->paint.fontInfo->fid) {
  983.         XSetFont(XtDisplay(new), new->paint.fgc, 
  984.                 new->paint.fontInfo->fid);
  985.     }
  986.     if (cur->paint.drawWidth  != new->paint.drawWidth || 
  987.         cur->paint.drawHeight != new->paint.drawHeight) {
  988.         UndoStack    *cur;
  989.  
  990.         /*
  991.         **  Resize the undo buffers
  992.         */
  993.         if (new->paint.paint == None) {
  994.             resizePixmap(new, &new->paint.base);
  995.             for (cur = new->paint.tail; cur != NULL; cur = cur->next) 
  996.                 resizePixmap(new, &cur->pixmap);
  997.         }
  998.         
  999.         /*
  1000.         **  Destroy the XImage that is cached
  1001.         */
  1002.         if (new->paint.image != NULL) {
  1003.             XDestroyImage(new->paint.image);
  1004.             XDestroyRegion(new->paint.imageRegion);
  1005.             new->paint.image = NULL;
  1006.         }
  1007.  
  1008.         if (XtMakeResizeRequest((Widget)new, 
  1009.                 new->paint.drawWidth * new->paint.zoom,
  1010.                 new->paint.drawHeight * new->paint.zoom,
  1011.                 NULL, NULL) == XtGeometryDone) {
  1012.             ret = True;
  1013.             sizeChanged = True;
  1014.         }
  1015.         for (i = 0; i < new->paint.paintChildrenSize; i++) {
  1016.             XtVaSetValues(new->paint.paintChildren[i], 
  1017.                     XtNdrawWidth, new->paint.drawWidth,
  1018.                     XtNdrawHeight, new->paint.drawHeight,
  1019.                     NULL);
  1020.         }
  1021.     }
  1022.     if (cur->paint.zoom != new->paint.zoom) {
  1023.         ret = True;
  1024.  
  1025.         if (XtMakeResizeRequest((Widget)new, 
  1026.                 new->paint.drawWidth * new->paint.zoom,
  1027.                 new->paint.drawHeight * new->paint.zoom,
  1028.                 NULL, NULL) == XtGeometryDone) {
  1029.             /*
  1030.             **   XXX  -- resize children  ???
  1031.             */
  1032.         }
  1033.         sizeChanged = True;
  1034.     }
  1035.     if (cur->paint.zoomX != new->paint.zoomX || 
  1036.         cur->paint.zoomY != new->paint.zoomY) {
  1037.         XExposeEvent    event;
  1038.  
  1039.         event.x      = 0;
  1040.         event.y      = 0;
  1041.         event.width  = new->core.width;
  1042.         event.height = new->core.height;
  1043.  
  1044.         realExposeProc(new, &event, False);
  1045.         pwRegionZoomPosChanged(new);
  1046.     }
  1047. #if 0
  1048.     if (cur->core.width != new->core.width ||
  1049.         cur->core.height != new->core.height) {
  1050.         int    rc =
  1051.         XtMakeResizeRequest((Widget)new, 
  1052.                 new->core.width, new->core.height, 
  1053.                 NULL, NULL);
  1054.         printf("rc = %d\n",rc);
  1055.     }
  1056. #endif
  1057.     if (cur->paint.grid != new->paint.grid) {
  1058.         XRectangle    *rect = GetRectangle(new);
  1059.  
  1060.         rect->x -= rect->x % new->paint.zoom + 1;
  1061.         rect->y -= rect->y % new->paint.zoom + 1;
  1062.  
  1063.         drawVisibleGrid(new, (Widget)new, 
  1064.                 new->paint.grid, GET_ZOOM(new),
  1065.                 rect->x, rect->y, 
  1066.                 rect->x + rect->width, rect->y + rect->height);
  1067.  
  1068.         for (i = 0; i < new->paint.paintChildrenSize; i++) {
  1069.             XtVaSetValues(new->paint.paintChildren[i], 
  1070.                         XtNgrid, new->paint.grid, 
  1071.                         NULL);
  1072.         }
  1073.     }
  1074.  
  1075.     if (cur->core.background_pixel != new->core.background_pixel)
  1076.         XSetForeground(XtDisplay(new), new->paint.igc, new->core.background_pixel);
  1077.  
  1078.     if (cur->paint.cursor != new->paint.cursor)
  1079.         XDefineCursor(XtDisplay(new), XtWindow(new), new->paint.cursor);
  1080.     
  1081.     if (sizeChanged)
  1082.         XtCallCallbackList((Widget)new, new->paint.sizecalls, NULL);
  1083.  
  1084.     return ret;
  1085. }
  1086. static void GetValuesHook(Widget w, ArgList args, Cardinal *nargs)
  1087. {
  1088.     PaintWidget    pw = (PaintWidget)w;
  1089.     PaintWidget    pp = (PaintWidget)pw->paint.paint;
  1090.     Arg        a;
  1091.     int        i;
  1092.  
  1093.     if (pp == None)
  1094.         return;
  1095.     
  1096.     for (i = 0; i < *nargs; i++) {
  1097.         char    *nm = args[i].name;
  1098.  
  1099.         if (strcmp(nm, XtNlineWidth) == 0)
  1100.             XtSetArg(a, XtNlineWidth, args[i].value);
  1101.         else if (strcmp(nm, XtNlineFillRule) == 0)
  1102.             XtSetArg(a, XtNlineFillRule, args[i].value);
  1103.         else if (strcmp(nm, XtNfillRule) == 0)
  1104.             XtSetArg(a, XtNfillRule, args[i].value);
  1105.         else if (strcmp(nm, XtNdrawWidth) == 0)
  1106.             XtSetArg(a, XtNdrawWidth, args[i].value);
  1107.         else if (strcmp(nm, XtNdrawHeight) == 0)
  1108.             XtSetArg(a, XtNdrawHeight, args[i].value);
  1109.         else
  1110.             continue;
  1111.         XtGetValues((Widget)pp, &a, 1);
  1112.     }
  1113. }
  1114.  
  1115. static int QueryGeometryProc(Widget w, XtWidgetGeometry *proposed,
  1116.                 XtWidgetGeometry *reply)
  1117. {
  1118.  
  1119. /*
  1120. **  Use the fact that the return values are ordered by "importance"
  1121. */
  1122. #define SETRET(ret,x)    ret = (x > ret) ? x : ret
  1123.     PaintWidget    pw = (PaintWidget)w;
  1124.     int        width  = pw->paint.drawWidth  * pw->paint.zoom;
  1125.     int        height = pw->paint.drawHeight * pw->paint.zoom;
  1126.  
  1127.     reply->request_mode = CWWidth | CWHeight;
  1128.     reply->width  = width;
  1129.     reply->height = height;
  1130.  
  1131. #if 0
  1132.     printf("In %d,%d   Out %d,%d\n",
  1133.             proposed->width, proposed->height,
  1134.             reply->width, reply->height);
  1135. #endif
  1136.  
  1137.     if (proposed->request_mode & (CWWidth | CWHeight) == (CWWidth | CWHeight) &&
  1138.         proposed->width == reply->width && proposed->height == reply->height)
  1139.         return XtGeometryNo;
  1140. #if 0
  1141.     else if (reply->width == w->core.width && reply->height == w->core.height)
  1142.         return XtGeometryNo;
  1143. #endif
  1144.     else
  1145.         return XtGeometryAlmost;
  1146. }
  1147.  
  1148. XImage *PwGetImage(Widget w, XRectangle *rect)
  1149. {
  1150.     PaintWidget    pw = (PaintWidget)w;
  1151.     Pixmap        pix = GET_PIXMAP(pw);
  1152.     Region        r;
  1153.     XRectangle    clean;
  1154.  
  1155.     if (pw->paint.paint != None)
  1156.         pw = (PaintWidget)pw->paint.paint;
  1157.  
  1158.  
  1159.     if (rect != NULL) {
  1160.         if (rect->x < 0) {
  1161.             clean.x = 0;
  1162.             clean.width = rect->width + rect->x;
  1163.         } else {
  1164.             clean.x = rect->x;
  1165.             clean.width = rect->width;
  1166.         }
  1167.         if (rect->y < 0) {
  1168.             clean.y = 0;
  1169.             clean.height = rect->height + rect->y;
  1170.         } else {
  1171.             clean.y = rect->y;
  1172.             clean.height = rect->height;
  1173.         }
  1174.         if (clean.width > pw->paint.drawWidth)    
  1175.             clean.width = pw->paint.drawWidth;
  1176.         if (clean.height > pw->paint.drawHeight)    
  1177.             clean.height = pw->paint.drawHeight;
  1178.     } else {
  1179.         clean.x = 0;
  1180.         clean.y = 0;
  1181.         clean.width = pw->paint.drawWidth;
  1182.         clean.height = pw->paint.drawHeight;
  1183.     }
  1184.  
  1185.     if (pw->paint.image == NULL) {
  1186.         pw->paint.image = XCreateImage(XtDisplay(w), pw->paint.visual,
  1187.                     pw->core.depth, ZPixmap, 0, NULL, 
  1188.                     pw->paint.drawWidth, pw->paint.drawHeight,
  1189.                     32, 0);
  1190.         pw->paint.image->data = (char*)XtMalloc(pw->paint.drawHeight * pw->paint.image->bytes_per_line);
  1191.         pw->paint.imageRegion = XCreateRegion();
  1192.         pw->paint.invalidateRegion = False;
  1193.     }
  1194.  
  1195.     if (pw->paint.invalidateRegion) {
  1196.         XDestroyRegion(pw->paint.imageRegion);
  1197.         pw->paint.imageRegion = XCreateRegion();
  1198.         pw->paint.invalidateRegion = False;
  1199.     }
  1200.  
  1201.     if (XRectInRegion(pw->paint.imageRegion, clean.x, clean.y,
  1202.                 clean.width, clean.height) == RectangleIn)
  1203.         return pw->paint.image;
  1204.  
  1205.     r = XCreateRegion();
  1206.     XUnionRectWithRegion(&clean, r, r);
  1207.     XSubtractRegion(r, pw->paint.imageRegion, r);
  1208.  
  1209.     XClipBox(r, &clean);
  1210.  
  1211.     /*
  1212.     **  Since this is "caching" grow the image sligtly over the
  1213.     **    requested size.
  1214.     */
  1215.     if ((clean.x -= 8) < 0) 
  1216.         clean.x = 0;
  1217.     if ((clean.y -= 8) < 0) 
  1218.         clean.y = 0;
  1219.     if ((clean.width += 16) > pw->paint.drawWidth - clean.x) 
  1220.         clean.width = pw->paint.drawWidth - clean.x;
  1221.     if ((clean.height += 16) > pw->paint.drawHeight - clean.y) 
  1222.         clean.height = pw->paint.drawHeight - clean.y;
  1223.  
  1224.     XGetSubImage(XtDisplay(pw), pix, clean.x, clean.y,
  1225.             clean.width, clean.height, AllPlanes, ZPixmap,
  1226.             pw->paint.image, clean.x, clean.y);
  1227.     XUnionRectWithRegion(&clean, pw->paint.imageRegion, 
  1228.                     pw->paint.imageRegion);
  1229.  
  1230.     XDestroyRegion(r);
  1231. #if 0
  1232. printf("num rects = %d\n", ((long*)pw->paint.imageRegion)[1]);
  1233. #endif
  1234.     return pw->paint.image;
  1235. }
  1236.  
  1237. void PwGetPixmap(Widget w, Pixmap *pix, int *width, int *height)
  1238. {
  1239.     PaintWidget    pw = (PaintWidget)w;
  1240.     *pix = None;
  1241.  
  1242.     if (pw->paint.paint != None) {
  1243.         PwGetPixmap((Widget)pw->paint.paint, pix, width, height);
  1244.         return;
  1245.     }
  1246.  
  1247.     if (width != NULL)
  1248.         *width  = pw->paint.drawWidth;
  1249.     if (height != NULL)
  1250.         *height = pw->paint.drawHeight;
  1251.  
  1252.     *pix= XCreatePixmap(XtDisplay(w), XtWindow(w), 
  1253.                 pw->paint.drawWidth, pw->paint.drawHeight,
  1254.                 pw->core.depth);
  1255.     PwUpdateDrawable(w, *pix, NULL);
  1256. }
  1257. Pixmap PwGetRawPixmap(Widget w)
  1258. {
  1259.     PaintWidget    pw = (PaintWidget)w;
  1260.  
  1261.     if (pw->paint.paint != None)
  1262.         return PwGetRawPixmap((Widget)pw->paint.paint);
  1263.  
  1264.     return GET_PIXMAP(pw);
  1265. }
  1266.  
  1267. static void pwSetPixmap(PaintWidget w, Pixmap pix, int flag)
  1268. {
  1269.     Window        root;
  1270.     int        x, y;
  1271.     unsigned int    width, height, bw, depth;
  1272.     
  1273.     XGetGeometry(XtDisplay(w), pix,
  1274.             &root, &x, &y, &width, &height, &bw, &depth);
  1275.  
  1276. depth = 2;
  1277.     if (depth == 1) {
  1278.         XCopyPlane(XtDisplay(w), pix, GET_PIXMAP(w),
  1279.             w->paint.gc, 0, 0, width, height, 0, 0, 1);
  1280.     } else {
  1281.         XCopyArea(XtDisplay(w), pix, GET_PIXMAP(w),
  1282.             w->paint.gc, 0, 0, width, height, 0, 0);
  1283.     }
  1284. }
  1285.  
  1286. static void fatCallback(Widget parent, XtPointer w, XtPointer rectArg)
  1287. {
  1288.     XRectangle    *rect = (XRectangle*)rectArg;
  1289.     PaintWidget    pw = (PaintWidget)w;
  1290.     XExposeEvent    event;
  1291.     int        zoom = GET_ZOOM(pw);
  1292.  
  1293.     /*
  1294.     **  Make this look like an expose event on the fatbits region
  1295.     */
  1296.     event.x      = (rect->x - pw->paint.zoomX) * zoom;
  1297.     event.y      = (rect->y - pw->paint.zoomY) * zoom;
  1298.     event.width  = rect->width * zoom;
  1299.     event.height = rect->height * zoom;
  1300.  
  1301.     realExposeProc(pw, &event, False);
  1302. }
  1303.  
  1304. void PwUpdate(Widget w, XRectangle *rect, Boolean force)
  1305. {
  1306.     PaintWidget    pw = (PaintWidget)w;
  1307.     PaintWidget    parent = (PaintWidget)pw->paint.paint;
  1308.     PaintWidget    usePW = (parent == None) ? pw : parent;
  1309.     XRectangle    all;
  1310.  
  1311.     if (rect == NULL) {
  1312.         if (pw->paint.undo == NULL) {
  1313.             all.x      = 0;
  1314.             all.y      = 0;
  1315.             all.width  = pw->core.width;
  1316.             all.height = pw->core.height;
  1317.             rect = &all;
  1318.         } else {
  1319.             rect = &pw->paint.undo->box;
  1320.         }
  1321.     } else {
  1322.         all.x = rect->x - pw->paint.lineWidth;
  1323.         all.y = rect->y - pw->paint.lineWidth;
  1324.         all.width = rect->width + pw->paint.lineWidth * 2;
  1325.         all.height = rect->height + pw->paint.lineWidth * 2;
  1326.         rect = &all;
  1327.     }
  1328.  
  1329.     /*
  1330.     **  If we have a caching image
  1331.     */
  1332.     if (usePW->paint.image != NULL && !usePW->paint.invalidateRegion) {
  1333. #if 0
  1334.         if (hadRect) {
  1335.             /* XXX - There should be some better way */
  1336.             if (((long*)usePW->paint.imageRegion)[1] > 100) {
  1337.                 usePW->paint.invalidateRegion = True;
  1338.             } else {
  1339.                 Region    r = XCreateRegion();
  1340.                 XUnionRectWithRegion(rect, r, r);
  1341.                 XSubtractRegion(usePW->paint.imageRegion, r, 
  1342.                         usePW->paint.imageRegion);
  1343.                 XDestroyRegion(r);
  1344.             }
  1345.         } else {
  1346.             usePW->paint.invalidateRegion = True;
  1347.         }
  1348. #else
  1349.         usePW->paint.invalidateRegion = True;
  1350. #endif
  1351.     }
  1352.  
  1353.     XtCallCallbackList((Widget)usePW, usePW->paint.fatcalls, 
  1354.                     (XtPointer)rect);
  1355.  
  1356.     if (force || pw->paint.zoom > 1 || parent != None) 
  1357.         fatCallback((Widget)usePW, (XtPointer)usePW, (XtPointer)rect);
  1358. }
  1359.  
  1360. /*
  1361. **  Update the current visual buffer with the contents
  1362. **   of the undo area, thus a pseudo-real time undo.
  1363. **   (it's not undo at all)
  1364. */
  1365. void PwUpdateFromLast(Widget w, XRectangle *rect) 
  1366. {
  1367.     Pixmap        pix;
  1368.     PaintWidget    pw = (PaintWidget)w;
  1369.     Pixmap        draw = GET_PIXMAP(pw);
  1370.     
  1371.     if (pw->paint.paint != None)
  1372.         pw = (PaintWidget)pw->paint.paint;
  1373.  
  1374.     /*
  1375.     **  If there is undoing enabled
  1376.     */
  1377.     if (pw->paint.undo == None) {
  1378.         pix = pw->paint.base;
  1379.     } else {
  1380.         if (pix = pw->paint.undo->next != NULL)
  1381.             pix = pw->paint.undo->next->pixmap;
  1382.         else
  1383.             pix = pw->paint.base;
  1384.     }
  1385.  
  1386.     XCopyArea(XtDisplay(w), pix, draw, pw->paint.gc,
  1387.             rect->x, rect->y, rect->width, rect->height,
  1388.             rect->x, rect->y);
  1389.     PwUpdate(w, rect, True);
  1390. }
  1391.  
  1392. /*
  1393. **  Bogus XXX
  1394. */
  1395. XRectangle *PwScaleRectangle(Widget w, XRectangle *src)
  1396. {
  1397.     static XRectangle    dst;
  1398.     PaintWidget        pw = (PaintWidget)w;
  1399.  
  1400.     return src;
  1401. }
  1402.  
  1403. void PwPutPixmap(Widget w, Pixmap pix)
  1404. {
  1405.     PaintWidget    pw = (PaintWidget)w;
  1406.     GC        gc = pw->paint.gc;
  1407.     Pixmap        dst;
  1408.     Window        root;
  1409.     int        x, y;
  1410.     unsigned int    width, height, bw, depth;
  1411.     XRectangle    rect;
  1412.  
  1413.     XGetGeometry(XtDisplay(w), pix, &root, &x, &y, &width, &height, &bw, &depth);
  1414.     rect.x = 0;
  1415.     rect.y = 0;
  1416.     rect.width = width;
  1417.     rect.height = height;
  1418.     dst = PwUndoStart(w, &rect);
  1419.     XCopyArea(XtDisplay(pw), pix, dst, gc, 0, 0,
  1420.             width, height, 0, 0);
  1421.     PwUpdate(w, &rect, True);
  1422. }
  1423.  
  1424. static void removeChild(Widget child, Widget w)
  1425. {
  1426.     PaintWidget    pw = (PaintWidget)w;
  1427.     int        i;
  1428.  
  1429.     for (i = 0; i < pw->paint.paintChildrenSize; i++)
  1430.         if (pw->paint.paintChildren[i] == child)
  1431.             break;
  1432.     for (i++; i < pw->paint.paintChildrenSize; i++)
  1433.         pw->paint.paintChildren[i-1] = pw->paint.paintChildren[i];
  1434.  
  1435.     pw->paint.paintChildrenSize--;
  1436.     
  1437.     XtRemoveCallback((Widget)w, XtNfatBack, fatCallback, (XtPointer)child);
  1438. }
  1439.  
  1440. void PwAddChild(Widget w, Widget child)
  1441. {
  1442.     PaintWidget    pw = (PaintWidget)w;
  1443.  
  1444.     if (pw->paint.paintChildren == NULL)
  1445.         pw->paint.paintChildren = (Widget*)XtMalloc(sizeof(Widget) * (pw->paint.paintChildrenSize + 2));
  1446.     else
  1447.         pw->paint.paintChildren = (Widget*)XtRealloc((XtPointer)pw->paint.paintChildren, sizeof(Widget) * (pw->paint.paintChildrenSize + 2));
  1448.     pw->paint.paintChildren[pw->paint.paintChildrenSize++] = child;
  1449.     XtAddCallback(child, XtNdestroyCallback, (XtCallbackProc)removeChild, (XtPointer)w);
  1450.     XtAddCallback(w, XtNfatBack, fatCallback, (XtPointer)child);
  1451. }
  1452.